package com.canaan.business.service.bill.impl;

import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.lang.Pair;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONUtil;
import com.canaan.business.common.enums.agv.AgvEnum;
import com.canaan.business.common.enums.agv.AgvTaskStateEnum;
import com.canaan.business.common.enums.inOutStock.*;
import com.canaan.business.common.enums.storehouse.StoreHouseLocationTypeEnum;
import com.canaan.business.common.enums.storehouse.StorehouseStockStatusEnum;
import com.canaan.business.common.helper.EmptyStockHelper;
import com.canaan.business.domain.agv.AgvTaskDispatch;
import com.canaan.business.domain.basic.WmsProduct;
import com.canaan.business.domain.basic.WmsStorehouse;
import com.canaan.business.domain.basic.WmsStorehouseLocation;
import com.canaan.business.domain.bill.*;
import com.canaan.business.domain.inOutStock.*;
import com.canaan.business.domain.storehouse.WmsStorehouseStock;
import com.canaan.business.domain.vo.*;
import com.canaan.business.mapper.bill.AdjustOutBillMapper;
import com.canaan.business.service.agv.IAgvTaskDispatchService;
import com.canaan.business.service.basic.IWmsProductService;
import com.canaan.business.service.basic.IWmsStorehouseLocationService;
import com.canaan.business.service.bill.*;
import com.canaan.business.service.inOutStock.*;
import com.canaan.business.service.storehouse.IStorehouseStockStrategyService;
import com.canaan.business.service.storehouse.IWmsStorehouseStockService;
import com.canaan.common.constant.PrefixConstants;
import com.canaan.common.core.redis.RedisCache;
import com.canaan.common.encrypt.PushEdiService;
import com.canaan.common.exception.ServiceException;
import com.canaan.common.utils.DateUtils;
import com.canaan.common.utils.SecurityUtils;
import com.canaan.common.utils.StringUtils;
import com.canaan.common.utils.TableNoUtil;
import com.canaan.system.service.ISysConfigService;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import javax.annotation.Resource;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 调拔出库单Service业务层处理
 *
 * @author ruoyi
 * @date 2023-02-01
 */
@Slf4j
@Service
public class AdjustOutBillServiceImpl implements IAdjustOutBillService {
    @Resource
    private AdjustOutBillMapper adjustOutBillMapper;
    @Resource
    private IWmsOutStockOrderService wmsOutStockOrderService;
    @Resource
    private IWmsProductService productService;
    @Resource
    private IAdjustOutBillDetailService adjustOutBillDetailService;
    @Resource
    private IStorehouseStockStrategyService storehouseStockStrategyService;
    @Resource
    private IWmsStorehouseStockService storehouseStockService;
    @Resource
    private IWmsStorehouseLocationService locationService;
    @Resource
    private IAdjustLocationBillService adjustLocationBillService;
    @Resource
    private IAdjustLocationBillDetailService adjustLocationBillDetailService;
    @Resource
    private ITrayDetailService trayDetailService;
    @Resource
    private IOutStockBillService outStockBillService;
    @Resource
    private IOutStockBillDetailService outStockBillDetailService;
    @Resource
    private ISplitBillService splitBillService;
    @Resource
    private ISplitBillDetailService splitBillDetailService;
    @Resource
    private IAgvTaskDispatchService agvTaskDispatchService;
    @Resource
    private IBillDetailRecordService billDetailRecordService;
    @Resource
    private ISysConfigService sysConfigService;
    @Resource
    private RedisCache redisCache;
    @Resource
    private EmptyStockHelper emptyStockHelper;
    @Resource
    private ITrayProductFreezeDetailService trayProductFreezeDetailService;
    @Resource
    private ITrayProductFreezeService trayProductFreezeService;
    /**
     * 查询调拔出库单
     *
     * @param id 调拔出库单主键
     * @return 调拔出库单
     */
    @Override
    public AdjustOutBill selectAdjustOutBillById(Long id) {
        return adjustOutBillMapper.selectAdjustOutBillById(id);
    }

    @Override
    public List<AdjustOutBill> selectAdjustOutBillListPageDatas(AdjustOutBill adjustOutBill) {
        return adjustOutBillMapper.selectAdjustOutBillListPageDatas(adjustOutBill);
    }

    /**
     * 查询调拔出库单列表
     *
     * @param adjustOutBill 调拔出库单
     * @return 调拔出库单
     */
    @Override
    public List<AdjustOutBill> selectAdjustOutBillList(AdjustOutBill adjustOutBill) {
        return adjustOutBillMapper.selectAdjustOutBillList(adjustOutBill);
    }

    /**
     * 新增调拔出库单
     *
     * @param adjustOutBill 调拔出库单
     * @return 结果
     */
    @Override
    public int insertAdjustOutBill(AdjustOutBill adjustOutBill) {
        if(StringUtils.isBlank(adjustOutBill.getNo())){
            adjustOutBill.setNo(PrefixConstants.TRANSFER_ISSUE+TableNoUtil.getNo(AdjustOutBill.class));
        }
        if(StringUtils.isEmpty(adjustOutBill.getCreateBy())){
            adjustOutBill.setCreateBy(SecurityUtils.getUsername());
        }

        adjustOutBill.setCreateTime(DateUtils.getNowDate());
        adjustOutBill.setStatus(OutOrderStatusEnum.NEW.getCode());
        return adjustOutBillMapper.insertAdjustOutBill(adjustOutBill);
    }

    /**
     * 批量新增调拔出库单
     *
     * @param adjustOutBillList 调拔出库单列表
     * @return 结果
     */
    @Override
    public int batchInsertAdjustOutBill(List<AdjustOutBill> adjustOutBillList) {
        String username = SecurityUtils.getUsername();
        Date currerTime = DateUtils.getNowDate();
        for (AdjustOutBill adjustOutBill : adjustOutBillList){
            if(StringUtils.isBlank(adjustOutBill.getNo())){
                adjustOutBill.setNo(TableNoUtil.getNo(AdjustOutBill.class));
            }
            adjustOutBill.setCreateBy(username);
            adjustOutBill.setCreateTime(currerTime);
        }
        int insertNum = 0;
        for (int i=0; i<adjustOutBillList.size();) {
            int endIndex = i+500;
            if (endIndex > adjustOutBillList.size()) {
                endIndex = adjustOutBillList.size();
            }
            insertNum = insertNum + adjustOutBillMapper.batchInsertAdjustOutBill(adjustOutBillList.subList(i, endIndex));
            i = endIndex;
        }
        return insertNum;
    }

    /**
     * 修改调拔出库单
     *
     * @param adjustOutBill 调拔出库单
     * @return 结果
     */
    @Override
    public int updateAdjustOutBill(AdjustOutBill adjustOutBill) {
        if(StringUtils.isEmpty(adjustOutBill.getUpdateBy())) {
            adjustOutBill.setUpdateTime(DateUtils.getNowDate());
        }
        return adjustOutBillMapper.updateAdjustOutBill(adjustOutBill);
    }

    /**
     * 批量修改调拔出库单
     *
     * @param adjustOutBillList 调拔出库单列表
     * @return 结果
     */
    @Override
    public int batchUpdateAdjustOutBill(List<AdjustOutBill> adjustOutBillList) {
        String username = SecurityUtils.getUsername();
        Date currerTime = DateUtils.getNowDate();
        for (AdjustOutBill adjustOutBill : adjustOutBillList){
            adjustOutBill.setUpdateBy(username);
            adjustOutBill.setUpdateTime(currerTime);
        }
        int updateNum = 0;
        for (int i=0; i<adjustOutBillList.size();) {
            int endIndex = i+500;
            if (endIndex > adjustOutBillList.size()) {
                endIndex = adjustOutBillList.size();
            }
            updateNum = updateNum + adjustOutBillMapper.batchUpdateAdjustOutBill(adjustOutBillList.subList(i, endIndex));
            i = endIndex;
        }
        return updateNum;
    }

    /**
     * 批量删除调拔出库单
     *
     * @param ids 需要删除的调拔出库单主键集合
     * @return 结果
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public int deleteAdjustOutBillByIds(Long[] ids) {
        AdjustOutBill bill = new AdjustOutBill();
        bill.setIds(CollUtil.toList(ids));
        List<AdjustOutBill> billList = this.selectAdjustOutBillList(bill);
        List<String> nos = billList.stream()
                .filter(e -> OutOrderStatusEnum.CANCEL_PENDING_CONFIRMATION.getCode().equals(e.getStatus())
                        || OutOrderStatusEnum.ACCOMPLISH.getCode().equals(e.getStatus()))
                .map(AdjustOutBill::getNo).collect(Collectors.toList());
        if(!nos.isEmpty()){
            throw new ServiceException("取消待确认或已完成状态的单据不能删除");
        }
        for (AdjustOutBill adjustOutBill : billList) {
            if(OutOrderStatusEnum.PICKING.getCode().equals(adjustOutBill.getStatus())){
                //校验进行中单据下的出入库单数据
                WmsOutStockOrder stockOrder = wmsOutStockOrderService.selectWmsOutStockOrderByRelOrderNo(adjustOutBill.getNo(), OutStockOrderTypeEnum.ADJUST.getCode());
                if(stockOrder != null && stockOrder.getTotalActualQty() > 0){
                    nos.add(adjustOutBill.getNo());
                }
            }
        }
        if(!nos.isEmpty()){
            throw new ServiceException(nos + "单据已有实际出库数量不能删除");
        }
        //出库单和出库单明细删除
        nos = billList.stream().map(AdjustOutBill::getNo).collect(Collectors.toList());
        wmsOutStockOrderService.deleteWmsOutStockOrderByRelOrderNosAndType(nos, OutStockOrderTypeEnum.ADJUST.getCode());
        return adjustOutBillMapper.deleteAdjustOutBillByIds(ids);
    }

    /**
     * 删除调拔出库单信息
     *
     * @param id 调拔出库单主键
     * @return 结果
     */
    @Override
    public int deleteAdjustOutBillById(Long id) {
        return adjustOutBillMapper.deleteAdjustOutBillById(id);
    }

    /**
     * 查询调拔出库单
     *
     * @param no 编号
     * @return 调拔出库单
     */
    @Override
    public AdjustOutBill selectAdjustOutBillByNo(String no) {
        return adjustOutBillMapper.selectAdjustOutBillByNo(no);
    }

    /**
     * 批量删除调拔出库单
     *
     * @param nos 需要删除的编号集合
     * @return 结果
     */
    @Override
    public int deleteAdjustOutBillByNos(String[] nos) {
        return adjustOutBillMapper.deleteAdjustOutBillByNos(nos);
    }

    /**
     * 删除调拔出库单信息
     *
     * @param no 编号
     * @return 结果
     */
    @Override
    public int deleteAdjustOutBillByNo(String no) {
        return adjustOutBillMapper.deleteAdjustOutBillByNo(no);
    }

    @Override
    public int complete(List<Long> ids) {
        AdjustOutBill bill = new AdjustOutBill();
        bill.setIds(ids);
        List<AdjustOutBill> billList = this.selectAdjustOutBillList(bill);
        billList = billList.stream().filter(e -> OutOrderStatusEnum.PICKING.getCode().equals(e.getStatus())).collect(Collectors.toList());
        if (billList.isEmpty()) {
            throw  new ServiceException("单据状态不是"+OutOrderStatusEnum.PICKING.getMessage());
        }
        for (AdjustOutBill adjustOutBill : billList) {
            WmsOutStockOrder wmsOutStockOrder = wmsOutStockOrderService.selectWmsOutStockOrderByRelOrderNo(adjustOutBill.getNo(), OutStockOrderTypeEnum.ADJUST.getCode());
            if (wmsOutStockOrder != null && OutOrderStatusEnum.ACCOMPLISH.getCode().equals(wmsOutStockOrder.getOrderStatus())) {
                adjustOutBill.setCompleteTime(DateUtils.getNowDate());
                adjustOutBill.setStatus(OutOrderStatusEnum.ACCOMPLISH.getCode());
            } else {
                throw new ServiceException("出库单未完成，关联编号：" + adjustOutBill.getNo());
            }
        }
        this.batchUpdateAdjustOutBill(billList);
        return 1;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public int confirm(List<Long> ids) {
        AdjustOutBill bill = new AdjustOutBill();
        bill.setIds(ids);
        List<AdjustOutBill> billList = this.selectAdjustOutBillList(bill);
        billList = billList.stream().filter(e -> OutOrderStatusEnum.NEW.getCode().equals(e.getStatus())).collect(Collectors.toList());
        if (billList.isEmpty()) {
            return 0;
        }
        billList.stream().forEach(e -> e.setStatus(OutOrderStatusEnum.PICKING.getCode()));
        this.batchUpdateAdjustOutBill(billList);

        //添加出库单
        for (AdjustOutBill adjustOutBill : billList) {
            AdjustOutBillDetail adjustOutBillDetail = new AdjustOutBillDetail();
            adjustOutBillDetail.setBillNo(adjustOutBill.getNo());
            List<AdjustOutBillDetail> billDetails = this.adjustOutBillDetailService.selectAdjustOutBillDetailList(adjustOutBillDetail);
            if (CollUtil.isEmpty(billDetails)) {
                throw new ServiceException("未维护明细数据");
            }
            List<StockDetailProductVo> stockDetailProductVos = new ArrayList<>();
            for (AdjustOutBillDetail billDetail : billDetails) {
                StockDetailProductVo detailProductVo = new StockDetailProductVo();
                detailProductVo.setProductNo(billDetail.getProductNo());
                detailProductVo.setOrderQty(billDetail.getQty());
                stockDetailProductVos.add(detailProductVo);
            }
            wmsOutStockOrderService.initBillStockOrder(adjustOutBill.getNo(), OutStockOrderTypeEnum.ADJUST.getCode(), stockDetailProductVos,"","");
        }
        return billList.size();
    }

    @Override
    public List<AdjustOutBillExportVo> exportList(AdjustOutBill adjustOutBill) {
        return adjustOutBillMapper.exportList(adjustOutBill);
    }

    @Override
    public List<String> importExcel(List<AdjustOutBillExportVo> list) {
        List<String> errList = new ArrayList<>();
        Map<String, List<AdjustOutBillExportVo>> groupMap = list.stream().collect(Collectors.groupingBy(e -> e.getAddress() + ":" + e.getConcat()));
        Set<String> groupKeys = groupMap.keySet();
        for (String groupKey : groupKeys) {
            String[] split = groupKey.split(":");
            String address = split[0];
            String concat = split[1];
            List<AdjustOutBillExportVo> adjustOutBillExportVos = groupMap.get(groupKey);
            AdjustOutBill adjustOutBill = new AdjustOutBill();
            adjustOutBill.setAddress(address);
            adjustOutBill.setConcat(concat);
            adjustOutBill.setTotalQty(adjustOutBillExportVos.stream().filter(e->e.getQty()!=null).mapToLong(e -> e.getQty()).sum());
            this.insertAdjustOutBill(adjustOutBill);

            List<AdjustOutBillDetail> details = new ArrayList<>();
            for (AdjustOutBillExportVo adjustInBillExportVo : adjustOutBillExportVos) {
                AdjustOutBillDetail adjustOutBillDetail = new AdjustOutBillDetail();
                adjustOutBillDetail.setBillNo(adjustInBillExportVo.getNo());
                adjustOutBillDetail.setQty(adjustInBillExportVo.getQty());
                adjustOutBillDetail.setProductNo(adjustInBillExportVo.getProductNo());
                WmsProduct wmsProduct = productService.selectWmsProductByProductNo(adjustInBillExportVo.getProductNo());
                if (wmsProduct == null) {
                    errList.add("无效物料编码：" + wmsProduct.getProductNo());
                    continue;
                }
                adjustOutBillDetail.setProductName(wmsProduct.getProductName());
                adjustOutBillDetail.setProductUnit(wmsProduct.getCompany());
                details.add(adjustOutBillDetail);
            }
            if (CollUtil.isNotEmpty(details)) {
                adjustOutBillDetailService.batchInsertAdjustOutBillDetail(details);
            }
        }
        return errList;
    }

    @Override
    @Transactional
    public int cancel(List<Long> ids) {
        AdjustOutBill bill = new AdjustOutBill();
        bill.setIds(ids);
        List<AdjustOutBill> billList = this.selectAdjustOutBillList(bill);
        billList = billList.stream().filter(e -> OutOrderStatusEnum.NEW.getCode().equals(e.getStatus())
                || OutOrderStatusEnum.PICKING.getCode().equals(e.getStatus())).collect(Collectors.toList());
        if (billList.isEmpty()) {
            return 0;
        }
        for (AdjustOutBill adjustOutBill : billList) {
            WmsOutStockOrder wmsOutStockOrder = wmsOutStockOrderService.selectWmsOutStockOrderByRelOrderNo(adjustOutBill.getNo(), OutStockOrderTypeEnum.ADJUST.getCode());
            if (wmsOutStockOrder!=null) {
                if (wmsOutStockOrder.getTotalActualQty() > 0){
                    throw new ServiceException("已出库不允许取消，单号：" + adjustOutBill.getNo());
                }
                wmsOutStockOrder.setOrderStatus(OutOrderStatusEnum.CANCEL.getCode());
                this.wmsOutStockOrderService.updateWmsOutStockOrder(wmsOutStockOrder);
            }
        }
        billList.stream().forEach(e -> e.setStatus(OutOrderStatusEnum.CANCEL.getCode()));
        this.batchUpdateAdjustOutBill(billList);
        return billList.size();
    }

    /**
     * 确认取消
     * @param bill 单据信息
     * @return 结果
     */
    @Override
    @Transactional(rollbackFor = Exception.class)
    public int confirmCancel(AdjustOutBill bill) {
        bill = this.selectAdjustOutBillById(bill.getId());
        if(bill == null){
            throw new ServiceException("单据不存在");
        }else if(!OutOrderStatusEnum.CANCEL_PENDING_CONFIRMATION.getCode().equals(bill.getStatus())){
            throw new ServiceException("该状态不是取消待确认，无法确认取消");
        }

        WmsOutStockOrder stockOrder = wmsOutStockOrderService.selectWmsOutStockOrderByRelOrderNo(bill.getNo(), OutStockOrderTypeEnum.ADJUST.getCode());
        if(stockOrder != null){
            stockOrder.setOrderStatus(OutOrderStatusEnum.CANCEL.getCode());
            wmsOutStockOrderService.updateWmsOutStockOrder(stockOrder);
        }
        bill.setStatus(OutOrderStatusEnum.CANCEL.getCode());
        return this.updateAdjustOutBill(bill);
    }

    public OutStockResultVo analyseOutStockLock(OutStockQueryVo outStockQueryVo){
        //解析得到出库的成品库位
        OutStockResultVo resultVo=storehouseStockStrategyService.selectAllOutStock(outStockQueryVo);
        List<WmsStorehouseStockVo> outStockVos=storehouseStockService.selectEmpWmsStorehouseOutStockList();

        for(OutStockBill item:resultVo.getOutStockBills()){
            if(OutOrderStatusEnum.ACCOMPLISH.getCode().equals(item.getOrderStatus())){
                continue;
            }
            //锁定源库位
            WmsStorehouseStock sourceStock=storehouseStockService.selectWmsStorehouseStockByLocationNo(item.getSourceLocation());
            if(sourceStock==null){
                throw new RuntimeException("源库位"+item.getSourceLocation()+"不存在库存数据");
            }
            if(StringUtils.isEmpty(sourceStock.getTrayNo())){
                continue;
            }
            sourceStock.setStatus(StorehouseStockStatusEnum.LOCK.getCode());
            storehouseStockService.updateWmsStorehouseStock(sourceStock);
            WmsStorehouseLocation sourceLocation=locationService.selectWmsStorehouseLocationByNo(sourceStock.getStorehouseLocationNo());
            if(sourceLocation==null){
                throw new RuntimeException("源库位"+sourceStock.getStorehouseLocationNo()+"不存在");
            }
            if(outStockVos.size()==0){
                continue;
            }
            WmsStorehouseStockVo stockVo=getStorehouseStock(item,outStockVos);
            if(stockVo==null){
                continue;
            }
            outStockVos.remove(stockVo);
            item.setDestLocation(stockVo.getStorehouseLocationNo());

            //锁定目标库位
            WmsStorehouseStock destStock=storehouseStockService.selectWmsStorehouseStockByLocationNo(item.getDestLocation());
            if(destStock==null){
                throw new RuntimeException("库位"+item.getDestLocation()+"不存在库存数据");
            }
            destStock.setStatus(StorehouseStockStatusEnum.LOCK.getCode());
            storehouseStockService.updateWmsStorehouseStock(destStock);
            WmsStorehouseLocation destLocation=locationService.selectWmsStorehouseLocationByNo(destStock.getStorehouseLocationNo());
            if(destLocation==null){
                throw new RuntimeException("源库位"+destStock.getStorehouseLocationNo()+"不存在");
            }
            //创建AGV任务
            agvTaskDispatchService.createTaskDispatch(item.getNo(),sourceLocation,destLocation, AgvEnum.TASK_TYPE.OUT,
                    sourceStock.getContainerNo(),sourceStock.getTrayNo());
            //分拣单设置库位
            List<SplitBill> splitBills=resultVo.getSplitBills().stream().filter(O->O.getRelOrderNo().equals(item.getNo())).collect(Collectors.toList());
            if(splitBills.size() != 0){
                SplitBill splitBill=splitBills.get(0);
                splitBill.setLocation(stockVo.getStorehouseLocationNo());
            }
            //分析是否调库单
            emptyStockHelper.generateAdjustLocation(sourceLocation.getNo(),sourceLocation.getIsInner(),sourceLocation.getInnerLocation(),item.getNo());
        }
        if(resultVo.getOutStockBills().size()!=0){
            outStockBillService.batchInsertOutStockBill(resultVo.getOutStockBills());
        }
        if(resultVo.getOutStockBillDetails().size()!=0){
            outStockBillDetailService.batchInsertOutStockBillDetail(resultVo.getOutStockBillDetails());
        }
        if(resultVo.getSplitBills().size()!=0){
            splitBillService.batchInsertSplitBill(resultVo.getSplitBills());
        }
        if(resultVo.getSplitBillDetails().size()!=0){
            splitBillDetailService.batchInsertSplitBillDetail(resultVo.getSplitBillDetails());
        }
        if(resultVo.getBillDetailRecords().size()!=0){
            billDetailRecordService.batchInsertBillDetailRecord(resultVo.getBillDetailRecords());
        }
        return resultVo;
    }


    /**
     * 解析出库
     */
    @Override
    public OutStockResultVo analyseOutStock(OutStockQueryVo outStockQueryVo){
        String key = "OUT_LOCK";

        //TODO 临时方案锁，后期处理
        String lock = redisCache.getCacheObject(key);
        if (StringUtils.equals(lock, "true")) {
            throw new RuntimeException("有上架任务正在进行中，请稍后再试");
        }
        redisCache.setCacheObject(key, "true");
        OutStockResultVo resultVo;
        try {
            resultVo = analyseOutStockLock(outStockQueryVo);
        } catch (Exception e) {
            e.printStackTrace();
            throw new RuntimeException(e.getMessage());
        } finally {
            //TODO 临时方案
            redisCache.setCacheObject(key, "false");
        }
        return resultVo;
    }

    /**
     * 解析出库
     */
    @Override
    public OutStockResultVo handlePreOutStockBill(String billNo,Integer billType,String address){
        String key = "OUT_LOCK";

        //TODO 临时方案锁，后期处理
        String lock = redisCache.getCacheObject(key);
        if (StringUtils.equals(lock, "true")) {
            throw new RuntimeException("有上架任务正在进行中，请稍后再试");
        }
        redisCache.setCacheObject(key, "true");
        OutStockResultVo outStockResultVo;
        try {
            outStockResultVo= handlePreOutStockFreezeLock(billNo,billType,address);
        } catch (Exception e) {
            e.printStackTrace();
            throw new RuntimeException(e.getMessage());
        } finally {
            //TODO 临时方案
            redisCache.setCacheObject(key, "false");
        }
        return outStockResultVo;
    }

    private OutStockResultVo handlePreOutStockFreezeLock(String billNo,Integer billType,String address){
        OutStockResultVo resultVo=analysePreOutStockFreezeLock(billNo,billType,address);
        List<WmsStorehouseStockVo> outStockVos=storehouseStockService.selectEmpWmsStorehouseOutStockList();

        for(OutStockBill item:resultVo.getOutStockBills()){
            //已经状态为完成则跳过，托盘已经出库
            if(OutOrderStatusEnum.ACCOMPLISH.getCode().equals(item.getOrderStatus())){
                continue;
            }
            //正在回库的出库单则跳过
            if("".equals(item.getDestLocation())){
                continue;
            }
            //锁定源库位
            WmsStorehouseStock sourceStock=storehouseStockService.selectWmsStorehouseStockByLocationNo(item.getSourceLocation());
            if(sourceStock==null){
                throw new RuntimeException("源库位"+item.getSourceLocation()+"不存在库存数据");
            }
            sourceStock.setStatus(StorehouseStockStatusEnum.LOCK.getCode());
            storehouseStockService.updateWmsStorehouseStock(sourceStock);
            WmsStorehouseLocation sourceLocation=locationService.selectWmsStorehouseLocationByNo(sourceStock.getStorehouseLocationNo());
            if(sourceLocation==null){
                throw new RuntimeException("源库位"+sourceStock.getStorehouseLocationNo()+"不存在");
            }
            if(outStockVos.size()==0){
                continue;
            }
            WmsStorehouseStockVo stockVo=getStorehouseStock(item,outStockVos);
            if(stockVo==null){
                continue;
            }
            outStockVos.remove(stockVo);
            item.setDestLocation(stockVo.getStorehouseLocationNo());

            //锁定目标库位
            WmsStorehouseStock destStock=storehouseStockService.selectWmsStorehouseStockByLocationNo(item.getDestLocation());
            if(destStock==null){
                throw new RuntimeException("库位"+item.getDestLocation()+"不存在库存数据");
            }
            destStock.setStatus(StorehouseStockStatusEnum.LOCK.getCode());
            storehouseStockService.updateWmsStorehouseStock(destStock);
            WmsStorehouseLocation destLocation=locationService.selectWmsStorehouseLocationByNo(destStock.getStorehouseLocationNo());
            if(destLocation==null){
                throw new RuntimeException("源库位"+destStock.getStorehouseLocationNo()+"不存在");
            }
            //创建AGV任务
            agvTaskDispatchService.createTaskDispatch(item.getNo(),sourceLocation,destLocation, AgvEnum.TASK_TYPE.OUT,
                    sourceStock.getContainerNo(),sourceStock.getTrayNo());
            //分拣单设置库位
            List<SplitBill> splitBills=resultVo.getSplitBills().stream().filter(O->O.getRelOrderNo().equals(item.getNo())).collect(Collectors.toList());
            if(splitBills.size() != 0){
                SplitBill splitBill=splitBills.get(0);
                splitBill.setLocation(stockVo.getStorehouseLocationNo());
            }
            //分析是否调库单
            emptyStockHelper.generateAdjustLocation(sourceLocation.getNo(),sourceLocation.getIsInner(),sourceLocation.getInnerLocation(),item.getNo());
        }

        if(resultVo.getOutStockBills().size()!=0){
            outStockBillService.batchInsertOutStockBill(resultVo.getOutStockBills());
        }
        if(resultVo.getOutStockBillDetails().size()!=0){
            outStockBillDetailService.batchInsertOutStockBillDetail(resultVo.getOutStockBillDetails());
        }
        if(resultVo.getSplitBills().size()!=0){
            splitBillService.batchInsertSplitBill(resultVo.getSplitBills());
        }
        if(resultVo.getSplitBillDetails().size()!=0){
            splitBillDetailService.batchInsertSplitBillDetail(resultVo.getSplitBillDetails());
        }
        if(resultVo.getBillDetailRecords().size()!=0){
            billDetailRecordService.batchInsertBillDetailRecord(resultVo.getBillDetailRecords());
        }
        return resultVo;
    }

    private OutStockResultVo analysePreOutStockFreezeLock(String billNo,Integer billType,String address){
        OutStockResultVo outStockResultVo=new OutStockResultVo();
        List<TrayProductFreezeDetail> freezeDetails=trayProductFreezeDetailService.selectTrayProductFreezeDetailByBillNo(billNo);
        if(freezeDetails==null||freezeDetails.size()==0){
            throw new RuntimeException("单据"+billNo+"不存在预出库明细数据");
        }
        List<String> freezeNos=freezeDetails.stream().map(TrayProductFreezeDetail::getFreezeNo).collect(Collectors.toList());
        TrayProductFreeze query=new TrayProductFreeze();
        query.setNos(freezeNos);
        query.setDelFlag("0");
        List<TrayProductFreeze> freezes=trayProductFreezeService.selectTrayProductFreezeList(query);
        if(freezes==null||freezes.size()==0){
            throw new RuntimeException("单据"+billNo+"不存在预出库数据");
        }
        List<OutStockBillDetail> outStockBillDetails=new ArrayList<>();
        List<OutStockBill> outStockBills=new ArrayList<>();
        List<BillDetailRecord> billDetailRecords=new ArrayList<>();
        List<SplitBill> splitBills=new ArrayList<>();
        List<SplitBillDetail> splitBillDetails=new ArrayList<>();
        //获取托盘集合数据
        List<String> trays=freezeDetails.stream().map(TrayProductFreezeDetail::getTrayNo).collect(Collectors.toList());
        for(String tray : trays){
            OutStockBill outStockBill=new OutStockBill();
            outStockBill.setNo("OUT"+TableNoUtil.getNo(OutStockBill.class));
            outStockBill.setRelOrderNo(billNo);
            outStockBill.setBillType(billType);
            outStockBill.setTrayNo(tray);
            outStockBill.setAddress(address);
            TrayDetail trayDetailQuery=new TrayDetail();
            trayDetailQuery.setTrayNo(tray);
            trayDetailQuery.setDelFlag("0");
            List<TrayDetail> trayDetails=trayDetailService.selectTrayDetailList(trayDetailQuery);
            if(trayDetails==null||trayDetails.size()==0){
                throw new RuntimeException("托盘"+tray+"不存在明细数据");
            }
            int trayTotal=0;
            int detailTotal=0;
            //出库明细
            for(TrayDetail trayDetail:trayDetails) {
                trayTotal+=trayDetail.getQty();
                OutStockBillDetail detail = new OutStockBillDetail();
                detail.setProductNo(trayDetail.getProductNo());
                detail.setProductName(trayDetail.getProductName());
                detail.setProductUnit(trayDetail.getProductUnit());
                detail.setStatus(OutOrderStatusEnum.NEW.getCode());
                detail.setNo(TableNoUtil.getNo(OutStockBillDetail.class));
                detail.setBatchNo(trayDetail.getBatchNo());
                detail.setOrderNo(outStockBill.getNo());
                List<TrayProductFreezeDetail> trayProductFreezeDetailList=freezeDetails.stream().filter(O->billNo.equals(O.getBillNo())&&
                        tray.equals(O.getTrayNo())&&trayDetail.getProductNo().equals(O.getProductNo())).collect(Collectors.toList());
                if(trayProductFreezeDetailList.size()==0){
                    continue;
                }
                TrayProductFreezeDetail trayProductFreezeDetail=trayProductFreezeDetailList.get(0);
                detail.setQty(trayProductFreezeDetail.getQty());
                outStockBillDetails.add(detail);
                detailTotal+=detail.getQty();
                //单据绑定纪录
                BillDetailRecord record=new BillDetailRecord();
                record.setStockStatus(trayDetail.getStockStatus());
                record.setBatchNo(trayDetail.getBatchNo());
                record.setBillType(billType);
                record.setBillNo(billNo);
                record.setTrayNo(tray);
                record.setQty(detail.getQty());
                record.setProductNo(trayDetail.getProductNo());
                record.setProductUnit(trayDetail.getProductUnit());
                record.setProductName(trayDetail.getProductName());
                record.setOperation(getBillOperation(billType));
                billDetailRecords.add(record);
            }

            WmsStorehouseStock trayStock=storehouseStockService.selectWmsStorehouseStockByTrayNo(tray);
            //当前托盘在搬运过程中
            if(trayStock==null){
                AgvTaskDispatch agvQuery=new AgvTaskDispatch();
                agvQuery.setTrayNo(tray);
                agvQuery.setDelFlag(0);
                List<AgvTaskDispatch> agvTaskDispatches=agvTaskDispatchService.selectAgvTaskDispatchList(agvQuery);
                if(agvTaskDispatches==null||agvTaskDispatches.size()==0){
                    throw new RuntimeException("托盘"+tray+"不存在AGV任务");
                }
                AgvTaskDispatch agvTaskDispatch=agvTaskDispatches.get(0);
                //正在出库
                if(AgvEnum.TASK_TYPE.OUT.getCode().equals(agvTaskDispatch.getTaskType())){
                    outStockBill.setSourceLocation(agvTaskDispatch.getStartLocationCode());
                    outStockBill.setDestLocation(agvTaskDispatch.getEndLocationCode());
                    outStockBill.setShelfNo(agvTaskDispatch.getShelfNo());
                    outStockBill.setOrderStatus(OutOrderStatusEnum.ACCOMPLISH.getCode());
                }
                else {
                    outStockBill.setOrderStatus(OutOrderStatusEnum.NEW.getCode());
                    outStockBill.setDestLocation("");
                    outStockBill.setSourceLocation(agvTaskDispatch.getEndLocationCode());
                    outStockBill.setShelfNo(agvTaskDispatch.getShelfNo());
                    //正在回库不创建分拣单
                    continue;
                }
            }
            else{
                WmsStorehouseLocation trayLocation=locationService.selectWmsStorehouseLocationByNo(trayStock.getStorehouseLocationNo());
                if(trayLocation==null){
                    throw new RuntimeException("库位"+trayStock.getStorehouseLocationNo()+"不存在");
                }
                List<AgvTaskDispatch> agvTaskDispatches=agvTaskDispatchService.selectAgvTaskDispatchListByStartPoint(trayLocation.getAgvPositionCode());
                //托盘还在库
                if(StoreHouseLocationTypeEnum.STORAGE.getCode().equals(trayLocation.getLocationType())){
                    //不存在AGV任务
                    if(agvTaskDispatches==null||agvTaskDispatches.size()==0) {
                        outStockBill.setSourceLocation(trayStock.getStorehouseLocationNo());
                        outStockBill.setShelfNo(trayStock.getContainerNo());
                        outStockBill.setDestLocation("");
                        outStockBill.setOrderStatus(OutOrderStatusEnum.NEW.getCode());
                    }
                    else{//已经存在Agv任务
                        AgvTaskDispatch agvTaskDispatch=agvTaskDispatches.get(0);
                        outStockBill.setSourceLocation(trayStock.getStorehouseLocationNo());
                        outStockBill.setShelfNo(trayStock.getContainerNo());
                        outStockBill.setDestLocation(agvTaskDispatch.getEndLocationCode());
                        outStockBill.setOrderStatus(OutOrderStatusEnum.ACCOMPLISH.getCode());
                    }
                }
                //托盘已经出库接驳位
                else if(StoreHouseLocationTypeEnum.OUT_DOCKING_STATION.getCode().equals(trayLocation.getLocationType())||
                        StoreHouseLocationTypeEnum.OUT_SORTING_STATION.getCode().equals(trayLocation.getLocationType())){
                    //不存在AGV任务
                    if(agvTaskDispatches==null||agvTaskDispatches.size()==0) {
                        outStockBill.setOrderStatus(OutOrderStatusEnum.ACCOMPLISH.getCode());
                        outStockBill.setDestLocation(trayStock.getStorehouseLocationNo());
                        outStockBill.setShelfNo(trayStock.getContainerNo());
                    }
                    else{
                        //正在回库不创建分拣单
                        AgvTaskDispatch agvTaskDispatch=agvTaskDispatches.get(0);
                        outStockBill.setOrderStatus(OutOrderStatusEnum.NEW.getCode());
                        outStockBill.setDestLocation("");
                        outStockBill.setSourceLocation(agvTaskDispatch.getEndLocationCode());
                        outStockBill.setShelfNo(agvTaskDispatch.getShelfNo());
                        continue;
                    }
                }
                outStockBills.add(outStockBill);
            }
            //创建分拣单
            if(detailTotal!=trayTotal&&detailTotal!=0){
                TrayProductFreezeDetail freezeDetailQuery=new TrayProductFreezeDetail();
                freezeDetailQuery.setTrayNo(tray);
                freezeDetailQuery.setDelFlag("0");
                List<TrayProductFreezeDetail> trayBillDetails=trayProductFreezeDetailService.selectTrayProductFreezeDetailList(freezeDetailQuery);
                Map<String,SplitBill> splitBillMap=new HashMap<>();
                for(TrayProductFreezeDetail item :trayBillDetails) {
                    SplitBill splitBill=null;
                    if(!splitBillMap.containsKey(item.getBillNo()+"_"+item.getTrayNo())){
                        splitBill=new SplitBill();
                        splitBill.setNo("S"+TableNoUtil.getNo(SplitBill.class));
                        splitBill.setOrderStatus(InOrderStatusEnum.NEW.getCode());
                        splitBill.setTrayNo(item.getTrayNo());
                        splitBill.setRelOrderNo(item.getBillNo());
                        splitBill.setRemark(item.getBillNo());
                        splitBills.add(splitBill);
                        splitBillMap.put(item.getBillNo()+"_"+item.getTrayNo(),splitBill);
                    }
                    else{
                        splitBill=splitBillMap.get(item.getBillNo()+"_"+item.getTrayNo());
                    }
                    splitBills.add(splitBill);
                    SplitBillDetail splitBillDetail=new SplitBillDetail();
                    splitBillDetail.setNo(TableNoUtil.getNo(SplitBillDetail.class));
                    splitBillDetail.setOrderNo(splitBill.getNo());
                    splitBillDetail.setProductNo(item.getProductNo());
                    splitBillDetail.setQty(item.getQty());
                    splitBillDetail.setStatus(OutOrderStatusEnum.NEW.getCode());
                    splitBillDetails.add(splitBillDetail);
                }
            }
        }
        outStockResultVo.setOutStockBills(outStockBills);
        outStockResultVo.setOutStockBillDetails(outStockBillDetails);
        outStockResultVo.setBillDetailRecords(billDetailRecords);
        outStockResultVo.setSplitBills(splitBills);
        outStockResultVo.setSplitBillDetails(splitBillDetails);
        return outStockResultVo;
    }


    /**
     * 获取单据操作
     */
    private String getBillOperation(Integer billType){
        if(ErpBillTypeEnum.ADJUST_OUT.getCode().equals(billType)){
            return ErpBillTypeEnum.ADJUST_OUT.getMessage();
        }
        else if(ErpBillTypeEnum.MODULATION_OUT.getCode().equals(billType)){
            return ErpBillTypeEnum.MODULATION_OUT.getMessage();
        }else{
            return ErpBillTypeEnum.PURCHASE_RETURN.getMessage();
        }
    }

    private void handleTrayFreeze(TrayProductFreeze trayProductFreeze){
        TrayProductFreezeDetail query=new TrayProductFreezeDetail();
        query.setTrayNo(trayProductFreeze.getTrayNo());
        query.setProductNo(trayProductFreeze.getProductNo());
        query.setDelFlag("0");
        List<TrayProductFreezeDetail> details=trayProductFreezeDetailService.selectTrayProductFreezeDetailList(query);
        if(details==null||details.size()==0){
            throw new RuntimeException("托盘"+trayProductFreeze.getTrayNo()+"物料"+trayProductFreeze.getProductNo()+"不存在预出库明细数据");
        }

    }
    /**
     * 处理预出库
     */
    private void handlePreOutStockBillLock(String billNo){
        OutStockBill query=new OutStockBill();
        query.setRelOrderNo(billNo);
        query.setDelFlag("0");
        List<OutStockBill> outStockBills=outStockBillService.selectOutStockBillList(query);
        if(outStockBills==null||outStockBills.size()==0){
            throw new RuntimeException("单据"+billNo+"不存在出库单");
        }

        List<WmsStorehouseStockVo> outStockVos=storehouseStockService.selectEmpWmsStorehouseOutStockList();
        for(OutStockBill item:outStockBills){
            //锁定源库位
            WmsStorehouseStock sourceStock=storehouseStockService.selectWmsStorehouseStockByTrayNo(item.getTrayNo());
            if(sourceStock==null){
                throw new RuntimeException("托盘不存在库存数据");
            }
            if(!StorehouseStockStatusEnum.FREEZE.getCode().equals(sourceStock.getStatus())){
                throw new RuntimeException("源库位"+sourceStock.getStorehouseLocationNo()+"不是Freeze状态");
            }
            sourceStock.setStatus(StorehouseStockStatusEnum.LOCK.getCode());
            storehouseStockService.updateWmsStorehouseStock(sourceStock);
            WmsStorehouseLocation sourceLocation=locationService.selectWmsStorehouseLocationByNo(sourceStock.getStorehouseLocationNo());
            if(sourceLocation==null){
                throw new RuntimeException("源库位"+sourceStock.getStorehouseLocationNo()+"不存在");
            }

            item.setSourceLocation(sourceStock.getStorehouseLocationNo());
            if(outStockVos.size()==0){
                item.setDestLocation("");
                outStockBillService.updateOutStockBill(item);
                continue;
            }
            WmsStorehouseStockVo stockVo=getStorehouseStock(item,outStockVos);
            if(stockVo==null){
                item.setDestLocation("");
                outStockBillService.updateOutStockBill(item);
                continue;
            }
            outStockVos.remove(stockVo);
            item.setSourceLocation(sourceStock.getStorehouseLocationNo());
            item.setDestLocation(stockVo.getStorehouseLocationNo());
            //锁定目标库位
            WmsStorehouseStock destStock=storehouseStockService.selectWmsStorehouseStockByLocationNo(item.getDestLocation());
            if(destStock==null){
                throw new RuntimeException("库位"+item.getDestLocation()+"不存在库存数据");
            }
            destStock.setStatus(StorehouseStockStatusEnum.LOCK.getCode());
            storehouseStockService.updateWmsStorehouseStock(destStock);
            WmsStorehouseLocation destLocation=locationService.selectWmsStorehouseLocationByNo(destStock.getStorehouseLocationNo());
            if(destLocation==null){
                throw new RuntimeException("源库位"+destStock.getStorehouseLocationNo()+"不存在");
            }
            //创建AGV任务
            agvTaskDispatchService.createTaskDispatch(item.getNo(),sourceLocation,destLocation, AgvEnum.TASK_TYPE.OUT,
                    sourceStock.getContainerNo(),sourceStock.getTrayNo());
            SplitBill splitBillQuery=new SplitBill();
            splitBillQuery.setRelOrderNo(item.getNo());
            splitBillQuery.setDelFlag("0");
            //分拣单设置库位
            List<SplitBill> splitBills=splitBillService.selectSplitBillList(splitBillQuery);
            if(splitBills.size() != 0){
                SplitBill splitBill=splitBills.get(0);
                splitBill.setLocation(stockVo.getStorehouseLocationNo());
                splitBillService.updateSplitBill(splitBill);
            }
            outStockBillService.updateOutStockBill(item);
            //分析是否调库单
            emptyStockHelper.generateAdjustLocation(sourceLocation.getNo(),sourceLocation.getIsInner(),sourceLocation.getInnerLocation(),item.getNo());
        }
    }


    /**
     * 获取相同出库库位
     * @param outStockBill 出库单
     * @param stockVos 出库库位集合
     * @return 出库库位
     */
    private WmsStorehouseStockVo getStorehouseStock(OutStockBill outStockBill,List<WmsStorehouseStockVo> stockVos){
        for(WmsStorehouseStockVo vo:stockVos){
            if(StoreHouseLocationTypeEnum.OUT_SORTING_STATION.getCode().equals(vo.getLocationType())&&
                    "1".equals(outStockBill.getIsSplit())){
                return vo;
            }
            else if(StoreHouseLocationTypeEnum.OUT_DOCKING_STATION.getCode().equals(vo.getLocationType())&&
                    "0".equals(outStockBill.getIsSplit())){
                return vo;
            }
        }
        return null;
    }


    /**
     * 入库回调
     */
    public void postOutStockCallback(String billNo,String stockStatus){
        OutStockCallbackVo inStockCallbackVo = new OutStockCallbackVo();
        inStockCallbackVo.setBizNo(billNo);
        inStockCallbackVo.setWmsBizNo(billNo);
        BillDetailRecord query=new BillDetailRecord();
        query.setBillNo(billNo);
        query.setDelFlag("0");

        List<BillDetailRecord> details=billDetailRecordService.selectBillDetailRecordList(query);
        List<GoodsVo> goodsVos=new ArrayList<>();
        Map<String,Long> map=new HashMap<>();
        for (BillDetailRecord item : details){
            if(!map.containsKey(item.getProductNo()+"_"+item.getProductUnit()+"_"+item.getBatchNo())){
                map.put(item.getProductNo()+"_"+item.getProductUnit()+"_"+item.getBatchNo(),item.getQty());
            }
            else{
                Long qty=map.get(item.getProductNo()+"_"+item.getProductUnit()+"_"+item.getBatchNo());
                map.put(item.getProductNo()+"_"+item.getProductUnit()+"_"+item.getBatchNo(),qty+item.getQty());
            }
        }
        for (String item: map.keySet()){
            String[] strAry=item.split("_");
            String productNo=strAry[0];
            String productUnit=strAry[1];
            String batchNo=strAry[2];
            GoodsVo goodsVo=new GoodsVo();
            goodsVo.setBatchNo(batchNo);
            goodsVo.setCode(productNo);
            goodsVo.setUnit(productUnit);
            goodsVo.setNum(map.get(item).toString());
            goodsVo.setStatus(Integer.parseInt(stockStatus));
            goodsVos.add(goodsVo);
        }
        inStockCallbackVo.setGoodDetails(goodsVos);
        SimpleDateFormat simpleDateFormat=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
        inStockCallbackVo.setDeliveryDate(simpleDateFormat.format(DateUtils.getNowDate()));
        // 发送入库回调
        if(Boolean.parseBoolean(sysConfigService.selectConfigByKey("edi.swtich"))){
            String str=JSONUtil.toJsonStr(inStockCallbackVo);
            log.info("inStock callback post = " + str);
            Pair<Boolean, String> result= PushEdiService.push(sysConfigService.selectConfigByKey("edi.outer"), str);
            log.info("post = " + result.getValue());
            if(!result.getKey()){
                throw new RuntimeException(result.getValue());
            }
        }
    }

    @Override
    public AdjustOutBillForPrintVo selectAdjustOutBillForPrint(String no) {
        return adjustOutBillMapper.selectAdjustOutBillForPrint(no);
    }
}
